#include "daemon_index.h"
#include "daemon.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LIST_SIZE 128

static int hash(const char *key) {
  int res = 1;

  for (int i = 0; i < strlen(key); i++) {
    res *= key[i];
  }

  return res % LIST_SIZE;
}

void di_free(daemon_index_t *d) {
  for (int i = 0; i < LIST_SIZE; i++) {
    if (d->list[i] == NULL)
      continue;

    daemon_index_entry_t *entry = d->list[i];
    daemon_index_entry_t *prev;

    while (entry != NULL) {
      printf("freeing entry with key \"%s\"\n", entry->key);
      free(entry->key);
      daemon_free(entry->daemon);
      prev = entry;
      entry = entry->next;
      free(prev);
    }
  }

  free(d->list);
  free(d);
}

daemon_index_t *di_create() {
  daemon_index_t *res = (daemon_index_t *)malloc(sizeof(daemon_index_t));
  res->list = (daemon_index_entry_t **)calloc(LIST_SIZE,
                                              sizeof(daemon_index_entry_t *));

  return res;
}

daemon_t *di_get(daemon_index_t *d, const char *key) {
  int index = hash(key);

  if (d->list[index] == NULL)
    return NULL;

  daemon_t *new = (daemon_t *)malloc(sizeof(daemon_t));
  daemon_index_entry_t *entry = d->list[index];
  while (strcmp(entry->key, key) != 0) {
    entry = entry->next;
    if (entry == NULL) {
      printf("di_get: error, key does not exist in the chain, but it should\n");
      return NULL;
    }
  }

  daemon_deep_copy(new, entry->daemon);
  return new;
}

int di_insert(daemon_index_t *d, const char *key, daemon_t *daemon) {
  int index = hash(key);

  // No collision
  if (d->list[index] == NULL) {
    d->list[index] =
        (daemon_index_entry_t *)malloc(sizeof(daemon_index_entry_t));
    d->list[index]->daemon = (daemon_t *)malloc(sizeof(daemon_t));
    daemon_deep_copy(d->list[index]->daemon, daemon);
    d->list[index]->key = (char *)malloc(sizeof(char) * strlen(key) + 1);
    strcpy(d->list[index]->key, key);
    printf("inserted an entry with key \"%s\" (no collision)\n", key);
    return 0;
  }

  daemon_index_entry_t *entry = d->list[index];

  while (entry->next != NULL) {
    // Entry already exists
    if (strcmp(entry->key, key) == 0) {
      printf("replacing entry \"%s\"\n", key);
      daemon_free(entry->daemon);
      entry->daemon = (daemon_t *)malloc(sizeof(daemon_t));
      daemon_deep_copy(entry->daemon, daemon);
      return 1;
    }

    entry = entry->next;
  }

  // Collision
  entry->next = (daemon_index_entry_t *)malloc(sizeof(daemon_index_entry_t));
  entry->next->daemon = (daemon_t *)malloc(sizeof(daemon_t));
  daemon_deep_copy(entry->next->daemon, daemon);
  entry->next->key = (char *)malloc(sizeof(char) * strlen(key) + 1);
  strcpy(entry->next->key, key);
  printf("inserted an entry with key \"%s\" (collision)\n", key);

  return 2;
}